package org.database.advice;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.database.annotation.ProtectedField;
import org.database.service.StorageAbstract;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.Objects;

/**
 * StorageAdvice
 *
 * @author grl
 * @date 2024/1/9
 */
@Order
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class EncryptAdvice {

    private final StorageAbstract storageAbstract;

    @Pointcut("@annotation(org.database.annotation.NeedEncrypt)")
    public void pointCut() {
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //加密
        encrypt(joinPoint);
        return joinPoint.proceed();
    }

    public void encrypt(ProceedingJoinPoint joinPoint) throws IllegalAccessException {
        Object[] objects;
        objects = joinPoint.getArgs();
        if (objects.length != 0) {
            for (int i = 0; i < objects.length; i++) {
                if (objects[i] instanceof String) {
                    objects[i] = encryptValue(objects, objects[i]);
                } else {
                    encryptObject(objects, objects[i]);
                }
            }
        }
    }

    /**
     * 加密对象
     *
     * @param obj
     * @throws IllegalAccessException
     */
    private void encryptObject(Object[] originalData, Object obj) throws IllegalAccessException {
        if (Objects.isNull(obj)) {
            log.info("当前需要加密的object为null");
            return;
        }
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            boolean containEncryptField = field.isAnnotationPresent(ProtectedField.class);
            if (containEncryptField) {
                field.setAccessible(true);
                String encrypt = storageAbstract.encrypt(originalData, String.valueOf(field.get(obj)));
                if (encrypt != null) {
                    field.set(obj, encrypt);
                }
            }
        }
    }

    /**
     * 加密单个值
     *
     * @param realValue
     * @return
     */
    public String encryptValue(Object[] originalData, Object realValue) {
        try {
            String encrypt = storageAbstract.encrypt(originalData, String.valueOf(realValue));
            return String.valueOf(encrypt);
        } catch (Exception e) {
            log.info("加密异常={}", e.getMessage());
        }
        return String.valueOf(realValue);
    }

}
